package org.example.storage;

import org.example.model.BetRecord;
import org.example.model.MonitoringMetrics;
import org.example.monitor.HealthStatus;
import org.example.monitor.Monitorable;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class BettingStorage implements Monitorable {
    // 主存储：betOfferId -> List<BetRecord> (保留原始数据)
    private final Map<Integer, List<BetRecord>> betsByOfferId = new ConcurrentHashMap<>();

    // 优化缓存：betOfferId -> TreeMap<stake, customerId> (按投注额排序)
    private final Map<Integer, TreeMap<Integer, Integer>> stakesCache = new ConcurrentHashMap<>();

    // 客户当前最高投注缓存：betOfferId -> Map<customerId, currentMaxStake>
    private final Map<Integer, Map<Integer, Integer>> customerCurrentStakes = new ConcurrentHashMap<>();



    @Override
    public void executeMonitorCycle() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalBetOffers", betsByOfferId.size());
        stats.put("totalCachedOffers", stakesCache.size());
        stats.put("totalCustomerStakes", customerCurrentStakes.size());

        long totalBets = betsByOfferId.values().stream().mapToLong(List::size).sum();
        stats.put("totalBets", totalBets);

        stats.put("customerCurrentStakes", customerCurrentStakes);
        stats.put("betsByOfferId", betsByOfferId);
        System.out.println("BettingStorage statistics:" + stats);
    }

    @Override
    public String getComponentName() {
        return "BettingStorage：";
    }

    @Override
    public MonitoringMetrics getMetrics() {
        return null;
    }

    @Override
    public HealthStatus getHealthStatus() {
        return HealthStatus.HEALTHY;
    }

    public void addBet(BetRecord bet) {
        // 保存原始记录
        betsByOfferId.computeIfAbsent(bet.getBetOfferId(), k -> new CopyOnWriteArrayList<>()).add(bet);

        // 更新缓存
        updateStakesCache(bet);
    }

    public String getHighStakesForOffer(int betOfferId) {
        TreeMap<Integer, Integer> stakes = stakesCache.get(betOfferId);
        if (stakes == null || stakes.isEmpty()) {
            return "";
        }
        // 使用entrySet直接获取前20个，避免创建中间集合
        return stakes.entrySet().stream()
                .limit(20)
                .map(entry -> entry.getValue() + "=" + entry.getKey())
                .collect(Collectors.joining(","));
    }

    /**
     * 备用的传统方法实现（如果没有使用缓存）
     */
    @Deprecated
    public String getHighStakesForOfferTraditional(int betOfferId) {
        List<BetRecord> bets = betsByOfferId.get(betOfferId);
        if (bets == null || bets.isEmpty()) {
            return "";
        }

        // 使用Stream处理：按客户分组，取每个客户的最高投注，然后排序
        List<String> topStakes = bets.stream()
                .collect(Collectors.groupingBy(
                        BetRecord::getCustomerId,
                        Collectors.collectingAndThen(
                                Collectors.maxBy(Comparator.comparingInt(BetRecord::getStake)),
                                Optional::get
                        )
                ))
                .values()
                .stream()
                .sorted((b1, b2) -> Integer.compare(b2.getStake(), b1.getStake()))
                .limit(20)
                .map(bet -> bet.getCustomerId() + "=" + bet.getStake())
                .collect(Collectors.toList());

        return String.join(",", topStakes);
    }


    public List<BetRecord> getBetsForOffer(int betOfferId) {
        return betsByOfferId.getOrDefault(betOfferId, new ArrayList<>());
    }


    /**
     * 获取客户在当前博彩项目中的最高投注额
     */
    private Integer getCurrentStakeForCustomer(int betOfferId, int customerId) {
        Map<Integer, Integer> customerStakes = customerCurrentStakes.get(betOfferId);
        if (customerStakes == null) {
            return null;
        }
        return customerStakes.get(customerId);
    }

    /**
     * 更新客户当前最高投注缓存
     */
    private void updateCustomerCurrentStake(int betOfferId, int customerId, int stake) {
        customerCurrentStakes.compute(betOfferId, (k, customerStakesMap) -> {
            if (customerStakesMap == null) {
                customerStakesMap = new ConcurrentHashMap<>();
            }
            customerStakesMap.put(customerId, stake);
            return customerStakesMap;
        });
    }

    private void updateStakesCache(BetRecord bet) {
        int betOfferId = bet.getBetOfferId();
        int customerId = bet.getCustomerId();
        int newStake = bet.getStake();

        // 先更新客户当前最高投注缓存
        Integer currentStake = getCurrentStakeForCustomer(betOfferId, customerId);
        if (currentStake == null || newStake > currentStake) {
            updateCustomerCurrentStake(betOfferId, customerId, newStake);

            // 更新排序缓存
            stakesCache.compute(betOfferId, (k, treeMap) -> {
                if (treeMap == null) {
                    treeMap = new TreeMap<>(Comparator.reverseOrder()); // 降序
                }

                // 移除该客户的旧记录（如果存在）
                if (currentStake != null) {
                    treeMap.remove(currentStake);
                }

                // 处理投注额重复的情况：使用复合key
                // 如果投注额相同，后到的覆盖先到的（或者可以添加时间戳）
                treeMap.put(newStake, customerId);
                return treeMap;
            });
        }
    }
}